﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Fixx.Connector;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using Fixx.DTO;

namespace FixxVS
{
	public partial class Issue : Form
	{
		private FixxPersistantStorage _Store { get; set; }
		private int IssueId { get; set; }
		private int ProjectId { get; set; }
		private FixxIssue _Issue { get; set; }
		private bool Changed { get; set; }
		private bool Initializing { get; set; }
		private bool IsClone { get; set; }
		private bool ResolutionChanged { get; set; }

		private Issue()
		{
			this.Changed = false;
			this.Initializing = true;
			InitializeComponent();
			this._Store = new FixxPersistantStorage();
			this._Issue = new FixxIssue();
		}
		public Issue(int projectId) : this()
		{
			this.ProjectId = projectId;
			this._LoadDataBindSources();
		}
		public Issue(int projectId, int issueId) : this()
		{
			this.IssueId = issueId;
			this.ProjectId = projectId;
			this._LoadDataBindSources();
		}
		public Issue(int projectId, int issueId, bool clone)
			: this()
		{
			this.IssueId = issueId;
			this.ProjectId = projectId;
			this.IsClone = true;
			this._LoadDataBindSources();
		}
		private void LoadIssue()
		{
			this.setBusy(true);
			lpView.Visible = true;
			lpEdit.Visible = false;

			this.Changed = false;
			this.Initializing = true;

			this._Store.Repository.GetIssueAsync(this.ProjectId, this.IssueId,
				(issue) =>
				{
					this._Issue = issue;
					if (this.IsClone)
					{
						this._Issue.Description = "";
						this._Issue.Title = "";
						this._Issue.Id = 0;
					}

					this.SafeInvoke(() =>
						{
							this.lblTitle.Text = this._Issue.Title;
							this.txbTitle.Text = this._Issue.Title;
							this.txbDescription.Text = Regex.Replace(issue.Description, "<br ?/?>", "\r\n");
							this.cbType.SelectedItem = this._Issue.IssueType;
							this.cbArea.SelectedItem = this._Issue.Area;
							this.cbFixFor.SelectedItem = this._Issue.FixForVersion;
							this.cbFoundIn.SelectedItem = this._Issue.AffectedVersion;
							this.cbAssignedTo.SelectedItem = this._Issue.AssignedTo;
							this.cbPriority.SelectedItem = this._Issue.Priority;
							this.cbResolution.SelectedItem = this._Issue.Resolution;
							this.cbClose.Checked = this._Issue.IsClosed;
							if (!this.IsClone)
							{
								string html = string.Format("<div style='overflow-y:auto;'>Posted by:<b>{0}</b><br />{1}</div>",
										issue.CreatedBy.Username, issue.Description
																.Replace("&gt;", ">")
																.Replace("&lt;", "<"));

								this._Store.Repository.GetCommentsAsync(this.ProjectId, this.IssueId,
									(comments) =>
									{
										this.SafeInvoke(() =>
										{
											comments.ToList().ForEach(c =>
												{
													Byte[] originalBytes = ASCIIEncoding.Default.GetBytes((c.CreatedBy.Email ?? "").ToLower().Trim());
													Byte[] encodedBytes = new MD5CryptoServiceProvider().ComputeHash(originalBytes);
													var hash = BitConverter.ToString(encodedBytes).Replace("-", "").ToLower();
													html += string.Format("<p style='clear:both'><div style='float:left'><b>{0}</b><br /><img src='http://www.gravatar.com/avatar/{3}?s=45&d=identicon' /></div><b>{2}</b><br />{1}</p>",
														c.CreatedBy.Username, c.Text, c.CreatedOn, hash);
												});
											this.wbDescription.Navigate("about:blank");
											HtmlDocument doc = this.wbDescription.Document;
											doc.Write(string.Empty);
											this.wbDescription.DocumentText = html;

											while (this.wbDescription.ReadyState != WebBrowserReadyState.Complete)
											{
												Application.DoEvents();
											}
											this.wbDescription.Document.Body.Style = "margin:0;padding-left:5px;padding:0;font-family:Microsoft Sans Serif;font-size:8.25pt;overflow-y:auto;";
											this.setBusy(false);
											this.Initializing = false;
										});
									},
									(error) =>
									{
									}
								);
							}
							else
							{
								lpView.Visible = false;
								lpEdit.Visible = true;
								this.tbMoreActions.Visible = false;
								this.tbEditActions.Visible = false;
								this.setBusy(false);
								this.Initializing = false;
							}
						});

				},
				(error) =>
				{
				}
			);
		}

		private void _LoadDataBindSources(int stackDepth)
		{
			if (stackDepth > 0)
			{
				this.DialogResult = DialogResult.Abort;
				return;
			}

			var cache = this._Store.Repository.GetProjectCache(this.ProjectId);
			if (cache == null)
			{
				this._Store.Repository.BootStrapProjectCache(this.ProjectId, () => this._LoadDataBindSources(++stackDepth));
				return;
			}

			this.bsTypes.DataSource = cache.IssueTypes;

			this.cbType.DataSource = cache.IssueTypes;
			this.cbType.DisplayMember = "Name";
			this.cbType.ValueMember = "Id";

			this.cbArea.DataSource = cache.Areas;
			this.cbArea.DisplayMember = "Name";
			this.cbArea.ValueMember = "Id";

			this.cbFixFor.DataSource = cache.Versions;
			this.cbFixFor.DisplayMember = "Name";
			this.cbFixFor.ValueMember = "Id";

			this.cbFoundIn.DataSource = cache.Versions;
			this.cbFoundIn.DisplayMember = "Name";
			this.cbFoundIn.ValueMember = "Id";

			this.cbAssignedTo.DataSource = this._Store.Repository.CachedUsers;
			this.cbAssignedTo.DisplayMember = "Username";
			this.cbAssignedTo.ValueMember = "Id";

			this.cbPriority.DataSource = this._Store.Repository.CachedPriorities;
			this.cbPriority.DisplayMember = "Name";
			this.cbPriority.ValueMember = "Id";

			this.cbResolution.DataSource = cache.Resolutions;
			this.cbResolution.DisplayMember = "Name";
			this.cbResolution.ValueMember = "Id";

			this.cbType.SelectedItem = null;
			this.cbArea.SelectedItem = null;
			this.cbFixFor.SelectedItem = null;
			this.cbFoundIn.SelectedItem = null;
			this.cbAssignedTo.SelectedItem = null;
			this.cbPriority.SelectedItem = null;
			this.cbResolution.SelectedItem = null;
		}

		private void _LoadDataBindSources()
		{
			this._LoadDataBindSources(0);
		}

		private void btnAddComment_Click(object sender, EventArgs e)
		{
			btnAddComment.Visible = false;
			btnSaveComment.Visible = true;
			btnCancelComment.Visible = true;
			btnEdit.Visible = false;
			splitComment.Panel2Collapsed = false;

			

		}

		private void OnCommentSaved(FixxComment comment)
		{
			btnAddComment.Visible = true;
			btnSaveComment.Visible = false;
			btnCancelComment.Visible = false;
			splitComment.Panel2Collapsed = true;
			btnEdit.Visible = true;
			this.setBusy(false);
			this.LoadIssue();
		}
		private void OnCommentSaved(FixxError error)
		{

		}

		private void btnCancelComment_Click(object sender, EventArgs e)
		{
			btnAddComment.Visible = true;
			btnSaveComment.Visible = false;
			btnCancelComment.Visible = false;
			splitComment.Panel2Collapsed = true;
			btnEdit.Visible = true;
		}

		private void btnSaveComment_Click(object sender, EventArgs e)
		{
			if (string.IsNullOrEmpty(this.txbComment.Text))
			{
				MessageBox.Show("comment cannot be empty!");
				return;
			}
			this.setBusy(true);
			this._Store.Repository.PostCommentAsync(
				this.IssueId,
				new FixxComment() { Text = this.txbComment.Text },
				(comment) => this.SafeInvoke(() => this.OnCommentSaved(comment)),
				(error) => this.SafeInvoke(() => this.OnCommentSaved(error))
			);
		}

		private void Issue_Load(object sender, EventArgs e)
		{
			if (this.IssueId > 0 && this.ProjectId > 0)
			{
				this.LoadIssue();
			}
			else
			{
				this.Changed = false;
				this.lblArea.ForeColor = Color.Red;
				lpView.Visible = false;
				lpEdit.Visible = true;
				this.tbMoreActions.Visible = false;
				this.tbEditActions.Visible = false;
				this.setBusy(false);
				this.Initializing = false;
			}
		}

		private void setBusy(bool busy)
		{
			this.lpIssue.Enabled = !busy;
			
			if (!busy && this.Changed)
			{
				this.btnOkNew.Enabled = true;
				this.btnOk.Enabled = true;
			}
			else
			{
				this.btnOkNew.Enabled = false;
				this.btnOk.Enabled = false;
			}
			this.pbBusy.Visible = busy;
		}

		private void btnOk_Click(object sender, EventArgs e)
		{
			if (this._Issue != null)
			{
				this.setBusy(true);
				this._Issue.AffectedVersion = (FixxVersion)this.cbFoundIn.SelectedItem;
				this._Issue.Area = (FixxArea)this.cbArea.SelectedItem;
				this._Issue.AssignedTo = (FixxUser)this.cbAssignedTo.SelectedItem;
				float f;
				if (float.TryParse(this.txbTimeEstimate.Text,out f))
					this._Issue.EstimatedTime = f;
				this._Issue.FixForVersion = (FixxVersion)this.cbFixFor.SelectedItem;
				if (this.cbClose.Checked)
				{
					if (!this._Issue.IsClosed)
					{
						this._Issue.ClosedOn = DateTime.Now;
					}
					this._Issue.IsClosed = true;
				}
				this._Issue.IssueType = (FixxIssueType)this.cbType.SelectedItem;
				this._Issue.Priority = (FixxPriority)this.cbPriority.SelectedItem;
				if (this._Issue.Resolution != (FixxResolution)this.cbResolution.SelectedItem)
				{
					this._Issue.ResolvedOn = DateTime.Now;
					this._Issue.ResolvedBy = this._Store.Repository.ActiveUser;
				}
				this._Issue.Resolution = (FixxResolution)this.cbResolution.SelectedItem;
				this._Issue.Title = this.txbTitle.Text;
				this._Issue.Description = this.txbDescription.Text;
				/*
				this._Store.Repository.PostIssue
				(	this.ProjectId, 
					this._Issue,
					(issue) => 
					{
						this.DialogResult = DialogResult.OK;
					}, 
					(error) => 
					{ 
					}
				);
				*/		
				
				this.setBusy(false);

			}
		}

		private void btnEdit_Click(object sender, EventArgs e)
		{
			lpView.Visible = false;
			lpEdit.Visible = true;
		}

		private void btnCancelEdit_Click(object sender, EventArgs e)
		{
			lpView.Visible = true;
			lpEdit.Visible = false;
		}
		private void cbResolution_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.cbClose.Enabled = (this.cbResolution.SelectedItem != null);
			this.onDropDownChange(sender, e);
		}
		

		private void onTextChange(object sender, EventArgs e)
		{
			this.onDropDownChange(sender, e);
		}

		private void cbClose_TextChanged(object sender, EventArgs e)
		{
			this.onDropDownChange(sender, e);
		}

		private void cbArea_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.lblArea.ForeColor = Color.Black;
			this.onDropDownChange(sender, e);
		}
		
		private void onDropDownChange(object sender, EventArgs e)
		{
			if (this.Initializing)
				return;
			if (this.lblArea.ForeColor == Color.Red)
				return;
			if (string.IsNullOrEmpty(this.txbDescription.Text))
				return;
			if (string.IsNullOrEmpty(this.txbTitle.Text))
				return;

			this.Changed = true;
			this.setBusy(false);
		}

		private void cbClose_Click(object sender, EventArgs e)
		{
			this.onDropDownChange(sender, e);
		}

		private void cbFixFor_SelectedIndexChanged(object sender, EventArgs e)
		{
			onDropDownChange(sender, e);
		}
	}
}
